{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "d760e6e6",
   "metadata": {},
   "source": [
    "# Portfolio Optimization using Second Order Cone\n",
    "\n",
    "In this notebook we show how to use the Second Order Cone (SOC) constraint in the variance portfolio optimization problem.\n",
    "\n",
    "## 1. Variance Optimization\n",
    "\n",
    "### 1.1 Variance Minimization\n",
    "\n",
    "The minimization of portfolio variance is a quadratic optimization problem that can be posed as:\n",
    "\n",
    "$$\n",
    "\\begin{equation}\n",
    "\\begin{aligned}\n",
    "& \\underset{x}{\\text{min}} & &  x^{\\tau} \\Sigma x \\\\\n",
    "& \\text{s.t.} & & \\mu x^{\\tau} \\geq \\bar{\\mu} \\\\\n",
    "& & &  \\sum_{i=1}^{N} x_i = 1 \\\\\n",
    "& & &  x_i \\geq 0 \\; ; \\; \\forall \\; i =1, \\ldots, N \\\\\n",
    "\\end{aligned}\n",
    "\\end{equation}\n",
    "$$\n",
    "\n",
    "Where $x$ are the weights of assets, $\\mu$ is the mean vector of expected returns and $\\bar{\\mu}$ the minimum expected return of portfolio."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "2a19278a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[*********************100%***********************]  25 of 25 completed\n"
     ]
    },
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>APA</th>\n",
       "      <th>BA</th>\n",
       "      <th>BAX</th>\n",
       "      <th>BMY</th>\n",
       "      <th>CMCSA</th>\n",
       "      <th>CNP</th>\n",
       "      <th>CPB</th>\n",
       "      <th>DE</th>\n",
       "      <th>HPQ</th>\n",
       "      <th>JCI</th>\n",
       "      <th>...</th>\n",
       "      <th>NI</th>\n",
       "      <th>PCAR</th>\n",
       "      <th>PSA</th>\n",
       "      <th>SEE</th>\n",
       "      <th>T</th>\n",
       "      <th>TGT</th>\n",
       "      <th>TMO</th>\n",
       "      <th>TXT</th>\n",
       "      <th>VZ</th>\n",
       "      <th>ZION</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2016-01-05</th>\n",
       "      <td>-2.0257%</td>\n",
       "      <td>0.4057%</td>\n",
       "      <td>0.4036%</td>\n",
       "      <td>1.9693%</td>\n",
       "      <td>0.0180%</td>\n",
       "      <td>0.9305%</td>\n",
       "      <td>0.3678%</td>\n",
       "      <td>0.5783%</td>\n",
       "      <td>0.9483%</td>\n",
       "      <td>-1.1953%</td>\n",
       "      <td>...</td>\n",
       "      <td>1.5881%</td>\n",
       "      <td>0.0212%</td>\n",
       "      <td>2.8236%</td>\n",
       "      <td>0.9758%</td>\n",
       "      <td>0.6987%</td>\n",
       "      <td>1.7539%</td>\n",
       "      <td>-0.1730%</td>\n",
       "      <td>0.2410%</td>\n",
       "      <td>1.3735%</td>\n",
       "      <td>-1.0857%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-06</th>\n",
       "      <td>-11.4863%</td>\n",
       "      <td>-1.5878%</td>\n",
       "      <td>0.2412%</td>\n",
       "      <td>-1.7557%</td>\n",
       "      <td>-0.7727%</td>\n",
       "      <td>-1.2473%</td>\n",
       "      <td>-0.1736%</td>\n",
       "      <td>-1.1239%</td>\n",
       "      <td>-3.5867%</td>\n",
       "      <td>-0.9551%</td>\n",
       "      <td>...</td>\n",
       "      <td>0.5547%</td>\n",
       "      <td>0.0212%</td>\n",
       "      <td>0.1592%</td>\n",
       "      <td>-1.5647%</td>\n",
       "      <td>-0.1466%</td>\n",
       "      <td>-1.0155%</td>\n",
       "      <td>-0.7653%</td>\n",
       "      <td>-3.0048%</td>\n",
       "      <td>-0.9034%</td>\n",
       "      <td>-2.9145%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-07</th>\n",
       "      <td>-5.1388%</td>\n",
       "      <td>-4.1922%</td>\n",
       "      <td>-1.6573%</td>\n",
       "      <td>-2.7699%</td>\n",
       "      <td>-1.1047%</td>\n",
       "      <td>-1.9769%</td>\n",
       "      <td>-1.2207%</td>\n",
       "      <td>-0.8855%</td>\n",
       "      <td>-4.6059%</td>\n",
       "      <td>-2.5394%</td>\n",
       "      <td>...</td>\n",
       "      <td>-2.2066%</td>\n",
       "      <td>-3.0309%</td>\n",
       "      <td>-1.0410%</td>\n",
       "      <td>-3.1557%</td>\n",
       "      <td>-1.6148%</td>\n",
       "      <td>-0.2700%</td>\n",
       "      <td>-2.2845%</td>\n",
       "      <td>-2.0570%</td>\n",
       "      <td>-0.5492%</td>\n",
       "      <td>-3.0020%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-08</th>\n",
       "      <td>0.2736%</td>\n",
       "      <td>-2.2705%</td>\n",
       "      <td>-1.6037%</td>\n",
       "      <td>-2.5425%</td>\n",
       "      <td>0.1099%</td>\n",
       "      <td>-0.2241%</td>\n",
       "      <td>0.5707%</td>\n",
       "      <td>-1.6402%</td>\n",
       "      <td>-1.7641%</td>\n",
       "      <td>-0.1649%</td>\n",
       "      <td>...</td>\n",
       "      <td>-0.1538%</td>\n",
       "      <td>-1.1366%</td>\n",
       "      <td>-0.7308%</td>\n",
       "      <td>-0.1449%</td>\n",
       "      <td>0.0895%</td>\n",
       "      <td>-3.3838%</td>\n",
       "      <td>-0.1117%</td>\n",
       "      <td>-1.1387%</td>\n",
       "      <td>-0.9720%</td>\n",
       "      <td>-1.1254%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2016-01-11</th>\n",
       "      <td>-4.3383%</td>\n",
       "      <td>0.1692%</td>\n",
       "      <td>-1.6851%</td>\n",
       "      <td>-1.0215%</td>\n",
       "      <td>0.0914%</td>\n",
       "      <td>-1.1792%</td>\n",
       "      <td>0.5674%</td>\n",
       "      <td>0.5288%</td>\n",
       "      <td>0.6616%</td>\n",
       "      <td>0.0330%</td>\n",
       "      <td>...</td>\n",
       "      <td>1.6436%</td>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.9869%</td>\n",
       "      <td>-0.1450%</td>\n",
       "      <td>1.2225%</td>\n",
       "      <td>1.4570%</td>\n",
       "      <td>0.5367%</td>\n",
       "      <td>-0.4607%</td>\n",
       "      <td>0.5800%</td>\n",
       "      <td>-1.9919%</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>5 rows × 25 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "                 APA       BA      BAX      BMY    CMCSA      CNP      CPB  \\\n",
       "Date                                                                         \n",
       "2016-01-05  -2.0257%  0.4057%  0.4036%  1.9693%  0.0180%  0.9305%  0.3678%   \n",
       "2016-01-06 -11.4863% -1.5878%  0.2412% -1.7557% -0.7727% -1.2473% -0.1736%   \n",
       "2016-01-07  -5.1388% -4.1922% -1.6573% -2.7699% -1.1047% -1.9769% -1.2207%   \n",
       "2016-01-08   0.2736% -2.2705% -1.6037% -2.5425%  0.1099% -0.2241%  0.5707%   \n",
       "2016-01-11  -4.3383%  0.1692% -1.6851% -1.0215%  0.0914% -1.1792%  0.5674%   \n",
       "\n",
       "                 DE      HPQ      JCI  ...       NI     PCAR      PSA  \\\n",
       "Date                                   ...                              \n",
       "2016-01-05  0.5783%  0.9483% -1.1953%  ...  1.5881%  0.0212%  2.8236%   \n",
       "2016-01-06 -1.1239% -3.5867% -0.9551%  ...  0.5547%  0.0212%  0.1592%   \n",
       "2016-01-07 -0.8855% -4.6059% -2.5394%  ... -2.2066% -3.0309% -1.0410%   \n",
       "2016-01-08 -1.6402% -1.7641% -0.1649%  ... -0.1538% -1.1366% -0.7308%   \n",
       "2016-01-11  0.5288%  0.6616%  0.0330%  ...  1.6436%  0.0000%  0.9869%   \n",
       "\n",
       "                SEE        T      TGT      TMO      TXT       VZ     ZION  \n",
       "Date                                                                       \n",
       "2016-01-05  0.9758%  0.6987%  1.7539% -0.1730%  0.2410%  1.3735% -1.0857%  \n",
       "2016-01-06 -1.5647% -0.1466% -1.0155% -0.7653% -3.0048% -0.9034% -2.9145%  \n",
       "2016-01-07 -3.1557% -1.6148% -0.2700% -2.2845% -2.0570% -0.5492% -3.0020%  \n",
       "2016-01-08 -0.1449%  0.0895% -3.3838% -0.1117% -1.1387% -0.9720% -1.1254%  \n",
       "2016-01-11 -0.1450%  1.2225%  1.4570%  0.5367% -0.4607%  0.5800% -1.9919%  \n",
       "\n",
       "[5 rows x 25 columns]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "####################################\n",
    "# Downloading Data\n",
    "####################################\n",
    "!pip install --quiet yfinance\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import yfinance as yf\n",
    "import warnings\n",
    "\n",
    "warnings.filterwarnings(\"ignore\")\n",
    "\n",
    "yf.pdr_override()\n",
    "pd.options.display.float_format = '{:.4%}'.format\n",
    "\n",
    "# Date range\n",
    "start = '2016-01-01'\n",
    "end = '2019-12-30'\n",
    "\n",
    "# Tickers of assets\n",
    "assets = ['JCI', 'TGT', 'CMCSA', 'CPB', 'MO', 'APA', 'MMC', 'JPM',\n",
    "          'ZION', 'PSA', 'BAX', 'BMY', 'LUV', 'PCAR', 'TXT', 'TMO',\n",
    "          'DE', 'MSFT', 'HPQ', 'SEE', 'VZ', 'CNP', 'NI', 'T', 'BA']\n",
    "assets.sort()\n",
    "\n",
    "# Downloading data\n",
    "data = yf.download(assets, start = start, end = end)\n",
    "data = data.loc[:,('Adj Close', slice(None))]\n",
    "data.columns = assets\n",
    "\n",
    "# Calculating returns\n",
    "Y = data[assets].pct_change().dropna()\n",
    "\n",
    "display(Y.head())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "583f7d9a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ECOS</th>\n",
       "      <th>SCS</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>APA</th>\n",
       "      <td>0.0002%</td>\n",
       "      <td>-0.0007%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>BA</th>\n",
       "      <td>0.0012%</td>\n",
       "      <td>0.0006%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>BAX</th>\n",
       "      <td>5.2647%</td>\n",
       "      <td>5.2662%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>BMY</th>\n",
       "      <td>4.3893%</td>\n",
       "      <td>4.3904%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CMCSA</th>\n",
       "      <td>2.1705%</td>\n",
       "      <td>2.1772%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CNP</th>\n",
       "      <td>6.9881%</td>\n",
       "      <td>6.9878%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CPB</th>\n",
       "      <td>3.2388%</td>\n",
       "      <td>3.2403%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>DE</th>\n",
       "      <td>0.0707%</td>\n",
       "      <td>0.0874%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>HPQ</th>\n",
       "      <td>0.0001%</td>\n",
       "      <td>-0.0005%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>JCI</th>\n",
       "      <td>2.8381%</td>\n",
       "      <td>2.8435%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>JPM</th>\n",
       "      <td>6.9786%</td>\n",
       "      <td>6.9421%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>LUV</th>\n",
       "      <td>2.8524%</td>\n",
       "      <td>2.8590%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MMC</th>\n",
       "      <td>12.5818%</td>\n",
       "      <td>12.6038%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MO</th>\n",
       "      <td>7.2325%</td>\n",
       "      <td>7.2291%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MSFT</th>\n",
       "      <td>0.0002%</td>\n",
       "      <td>-0.0006%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>NI</th>\n",
       "      <td>11.4513%</td>\n",
       "      <td>11.4451%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>PCAR</th>\n",
       "      <td>0.0003%</td>\n",
       "      <td>-0.0019%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>PSA</th>\n",
       "      <td>14.9188%</td>\n",
       "      <td>14.9124%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>SEE</th>\n",
       "      <td>0.1563%</td>\n",
       "      <td>0.1671%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>T</th>\n",
       "      <td>6.4205%</td>\n",
       "      <td>6.4208%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TGT</th>\n",
       "      <td>4.0908%</td>\n",
       "      <td>4.0965%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TMO</th>\n",
       "      <td>0.0004%</td>\n",
       "      <td>0.0005%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TXT</th>\n",
       "      <td>0.0007%</td>\n",
       "      <td>-0.0021%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>VZ</th>\n",
       "      <td>8.3448%</td>\n",
       "      <td>8.3447%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>ZION</th>\n",
       "      <td>0.0087%</td>\n",
       "      <td>-0.0074%</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          ECOS      SCS\n",
       "APA    0.0002% -0.0007%\n",
       "BA     0.0012%  0.0006%\n",
       "BAX    5.2647%  5.2662%\n",
       "BMY    4.3893%  4.3904%\n",
       "CMCSA  2.1705%  2.1772%\n",
       "CNP    6.9881%  6.9878%\n",
       "CPB    3.2388%  3.2403%\n",
       "DE     0.0707%  0.0874%\n",
       "HPQ    0.0001% -0.0005%\n",
       "JCI    2.8381%  2.8435%\n",
       "JPM    6.9786%  6.9421%\n",
       "LUV    2.8524%  2.8590%\n",
       "MMC   12.5818% 12.6038%\n",
       "MO     7.2325%  7.2291%\n",
       "MSFT   0.0002% -0.0006%\n",
       "NI    11.4513% 11.4451%\n",
       "PCAR   0.0003% -0.0019%\n",
       "PSA   14.9188% 14.9124%\n",
       "SEE    0.1563%  0.1671%\n",
       "T      6.4205%  6.4208%\n",
       "TGT    4.0908%  4.0965%\n",
       "TMO    0.0004%  0.0005%\n",
       "TXT    0.0007% -0.0021%\n",
       "VZ     8.3448%  8.3447%\n",
       "ZION   0.0087% -0.0074%"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "####################################\n",
    "# Minimizing Portfolio Variance\n",
    "####################################\n",
    "\n",
    "import cvxpy as cp\n",
    "from timeit import default_timer as timer\n",
    "\n",
    "# Defining initial inputs\n",
    "mu = Y.mean().to_numpy().reshape(1,-1)\n",
    "sigma = Y.cov().to_numpy()\n",
    "\n",
    "# Defining initial variables\n",
    "x = cp.Variable((mu.shape[1], 1))\n",
    "\n",
    "# Budget and weights constraints\n",
    "constraints = [cp.sum(x) == 1,\n",
    "               x <= 1,\n",
    "               x >= 0]\n",
    "\n",
    "# Defining risk objective\n",
    "risk = cp.quad_form(x, sigma)\n",
    "objective = cp.Minimize(risk)\n",
    "\n",
    "weights = pd.DataFrame([])\n",
    "# Solving the problem with several solvers\n",
    "prob = cp.Problem(objective, constraints)\n",
    "solvers = ['ECOS', 'SCS']\n",
    "for i in solvers:\n",
    "    prob.solve(solver=i)\n",
    "    # Showing Optimal Weights\n",
    "    weights_1 = pd.DataFrame(x.value, index=assets, columns=[i])\n",
    "    weights = pd.concat([weights, weights_1], axis=1)\n",
    "\n",
    "display(weights)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9661b089",
   "metadata": {},
   "source": [
    "As we can see the use of CVXPY's __quad_form__ in portfolio optimization can give small negative values to weights that must be zero."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "80c95d46",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ECOS</th>\n",
       "      <th>SCS</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Return</th>\n",
       "      <td>12.8507%</td>\n",
       "      <td>12.8498%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Std. Dev.</th>\n",
       "      <td>10.3737%</td>\n",
       "      <td>10.3738%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Variance</th>\n",
       "      <td>1.0761%</td>\n",
       "      <td>1.0761%</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              ECOS      SCS\n",
       "Return    12.8507% 12.8498%\n",
       "Std. Dev. 10.3737% 10.3738%\n",
       "Variance   1.0761%  1.0761%"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Calculating Annualized Portfolio Stats\n",
    "var = weights * (Y.cov() @ weights) * 252\n",
    "var = var.sum().to_frame().T\n",
    "std = np.sqrt(var)\n",
    "ret = Y.mean().to_frame().T @ weights * 252\n",
    "\n",
    "stats = pd.concat([ret, std, var], axis=0)\n",
    "stats.index = ['Return', 'Std. Dev.', 'Variance']\n",
    "\n",
    "display(stats)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a4900343",
   "metadata": {},
   "source": [
    "### 1.2 Return Maximization with Variance Constraint\n",
    "\n",
    "The maximization of portfolio return is a problem with a quadratic constraint that can be posed as:\n",
    "\n",
    "$$\n",
    "\\begin{equation}\n",
    "\\begin{aligned}\n",
    "& \\underset{x}{\\text{max}} & & \\mu x^{\\tau} \\\\\n",
    "& \\text{s.t.} & & x^{\\tau} \\Sigma x \\leq \\bar{\\sigma}^{2} \\\\\n",
    "& & & \\sum_{i=1}^{N} x_i = 1 \\\\\n",
    "& & &  x_i \\geq 0 \\; ; \\; \\forall \\; i =1, \\ldots, N \\\\\n",
    "\\end{aligned}\n",
    "\\end{equation}\n",
    "$$\n",
    "\n",
    "Where $x$ are the weights of assets and $\\bar{\\sigma}$ is the maximum expected standard deviation of portfolio.."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "f04e0f69",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ECOS</th>\n",
       "      <th>SCS</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>APA</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0006%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>BA</th>\n",
       "      <td>9.5892%</td>\n",
       "      <td>9.6764%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>BAX</th>\n",
       "      <td>12.6176%</td>\n",
       "      <td>12.5937%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>BMY</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0051%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CMCSA</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0072%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CNP</th>\n",
       "      <td>3.7021%</td>\n",
       "      <td>3.2811%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CPB</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0089%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>DE</th>\n",
       "      <td>6.2565%</td>\n",
       "      <td>6.3273%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>HPQ</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>-0.0003%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>JCI</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0053%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>JPM</th>\n",
       "      <td>6.5739%</td>\n",
       "      <td>6.5254%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>LUV</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0048%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MMC</th>\n",
       "      <td>18.7461%</td>\n",
       "      <td>18.5184%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MO</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0161%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MSFT</th>\n",
       "      <td>35.7121%</td>\n",
       "      <td>36.2356%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>NI</th>\n",
       "      <td>0.0278%</td>\n",
       "      <td>0.0099%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>PCAR</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0008%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>PSA</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0179%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>SEE</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0057%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>T</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0126%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TGT</th>\n",
       "      <td>6.7741%</td>\n",
       "      <td>6.7077%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TMO</th>\n",
       "      <td>0.0002%</td>\n",
       "      <td>0.0011%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TXT</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0028%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>VZ</th>\n",
       "      <td>0.0001%</td>\n",
       "      <td>0.0117%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>ZION</th>\n",
       "      <td>0.0001%</td>\n",
       "      <td>-0.0002%</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          ECOS      SCS\n",
       "APA    0.0000%  0.0006%\n",
       "BA     9.5892%  9.6764%\n",
       "BAX   12.6176% 12.5937%\n",
       "BMY    0.0000%  0.0051%\n",
       "CMCSA  0.0000%  0.0072%\n",
       "CNP    3.7021%  3.2811%\n",
       "CPB    0.0000%  0.0089%\n",
       "DE     6.2565%  6.3273%\n",
       "HPQ    0.0000% -0.0003%\n",
       "JCI    0.0000%  0.0053%\n",
       "JPM    6.5739%  6.5254%\n",
       "LUV    0.0000%  0.0048%\n",
       "MMC   18.7461% 18.5184%\n",
       "MO     0.0000%  0.0161%\n",
       "MSFT  35.7121% 36.2356%\n",
       "NI     0.0278%  0.0099%\n",
       "PCAR   0.0000%  0.0008%\n",
       "PSA    0.0000%  0.0179%\n",
       "SEE    0.0000%  0.0057%\n",
       "T      0.0000%  0.0126%\n",
       "TGT    6.7741%  6.7077%\n",
       "TMO    0.0002%  0.0011%\n",
       "TXT    0.0000%  0.0028%\n",
       "VZ     0.0001%  0.0117%\n",
       "ZION   0.0001% -0.0002%"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#########################################\n",
    "# Maximizing Portfolio Return with\n",
    "# Variance Constraint\n",
    "#########################################\n",
    "\n",
    "import cvxpy as cp\n",
    "from timeit import default_timer as timer\n",
    "\n",
    "# Defining initial inputs\n",
    "mu = Y.mean().to_numpy().reshape(1,-1)\n",
    "sigma = Y.cov().to_numpy()\n",
    "\n",
    "# Defining initial variables\n",
    "x = cp.Variable((mu.shape[1], 1))\n",
    "sigma_hat = 15 / (252**0.5 * 100)\n",
    "ret = mu @ x\n",
    "\n",
    "# Budget and weights constraints\n",
    "constraints = [cp.sum(x) == 1,\n",
    "               x <= 1,\n",
    "               x >= 0]\n",
    "\n",
    "# Defining risk constraint and objective\n",
    "risk = cp.quad_form(x, sigma)\n",
    "constraints += [risk <= sigma_hat**2] # variance constraint\n",
    "objective = cp.Maximize(ret)\n",
    "\n",
    "weights = pd.DataFrame([])\n",
    "# Solving the problem with several solvers\n",
    "prob = cp.Problem(objective, constraints)\n",
    "solvers = ['ECOS', 'SCS']\n",
    "for i in solvers:\n",
    "    prob.solve(solver=i)\n",
    "    # Showing Optimal Weights\n",
    "    weights_1 = pd.DataFrame(x.value, index=assets, columns=[i])\n",
    "    weights = pd.concat([weights, weights_1], axis=1)\n",
    "\n",
    "display(weights)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "54f4e088",
   "metadata": {},
   "source": [
    "The small negative values also appear when we use CVXPY's __quad_form__ in constraints."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "298f0630",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ECOS</th>\n",
       "      <th>SCS</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Return</th>\n",
       "      <td>26.0352%</td>\n",
       "      <td>26.1001%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Std. Dev.</th>\n",
       "      <td>15.0000%</td>\n",
       "      <td>15.0672%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Variance</th>\n",
       "      <td>2.2500%</td>\n",
       "      <td>2.2702%</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              ECOS      SCS\n",
       "Return    26.0352% 26.1001%\n",
       "Std. Dev. 15.0000% 15.0672%\n",
       "Variance   2.2500%  2.2702%"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Calculating Annualized Portfolio Stats\n",
    "var = weights * (Y.cov() @ weights) * 252\n",
    "var = var.sum().to_frame().T\n",
    "std = np.sqrt(var)\n",
    "ret = Y.mean().to_frame().T @ weights * 252\n",
    "\n",
    "stats = pd.concat([ret, std, var], axis=0)\n",
    "stats.index = ['Return', 'Std. Dev.', 'Variance']\n",
    "\n",
    "display(stats)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3459910a",
   "metadata": {},
   "source": [
    "## 2 Standard Deviation Optimization\n",
    "\n",
    "### 2.1 Standard Deviation Minimization\n",
    "\n",
    "An alternative problem is to minimize the standard deviation (square root of variance). To do this we can use the SOC constraint. The minimization of portfolio standard deviation can be posed as:\n",
    "\n",
    "$$\n",
    "\\begin{equation}\n",
    "\\begin{aligned}\n",
    "& \\underset{x}{\\text{min}} & &  g \\\\\n",
    "& \\text{s.t.} & & \\mu x^{\\tau} \\geq \\bar{\\mu} \\\\\n",
    "& & &  \\sum_{i=1}^{N} x_i = 1 \\\\\n",
    "& & & \\left\\|\\Sigma^{1/2} x\\right\\| \\leq g \\\\\n",
    "& & &  x_i \\geq 0 \\; ; \\; \\forall \\; i =1, \\ldots, N  \\\\\n",
    "\\end{aligned}\n",
    "\\end{equation}\n",
    "$$\n",
    "\n",
    "Where $\\left\\|\\Sigma^{1/2} x\\right\\| \\leq g$ is the SOC constraint, $x$ are the weights of assets, $\\mu$ is the mean vector of expected returns, $\\bar{\\mu}$ the minimum expected return of portfolio and $r$ is the matrix of observed returns.\n",
    "\n",
    "__Note:__ the SOC constraint can be expressed as $(g,\\Sigma^{1/2} x) \\in Q^{n+1}$, this notation is used to model the __SOC constraint__ in CVXPY."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "c85ededb",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ECOS</th>\n",
       "      <th>SCS</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>APA</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0000%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>BA</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0001%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>BAX</th>\n",
       "      <td>5.2634%</td>\n",
       "      <td>5.2632%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>BMY</th>\n",
       "      <td>4.3887%</td>\n",
       "      <td>4.3886%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CMCSA</th>\n",
       "      <td>2.1705%</td>\n",
       "      <td>2.1705%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CNP</th>\n",
       "      <td>6.9872%</td>\n",
       "      <td>6.9870%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CPB</th>\n",
       "      <td>3.2390%</td>\n",
       "      <td>3.2391%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>DE</th>\n",
       "      <td>0.0789%</td>\n",
       "      <td>0.0791%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>HPQ</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0002%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>JCI</th>\n",
       "      <td>2.8376%</td>\n",
       "      <td>2.8375%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>JPM</th>\n",
       "      <td>6.9842%</td>\n",
       "      <td>6.9839%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>LUV</th>\n",
       "      <td>2.8523%</td>\n",
       "      <td>2.8522%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MMC</th>\n",
       "      <td>12.5805%</td>\n",
       "      <td>12.5803%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MO</th>\n",
       "      <td>7.2314%</td>\n",
       "      <td>7.2313%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MSFT</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0003%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>NI</th>\n",
       "      <td>11.4509%</td>\n",
       "      <td>11.4508%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>PCAR</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0001%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>PSA</th>\n",
       "      <td>14.9186%</td>\n",
       "      <td>14.9183%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>SEE</th>\n",
       "      <td>0.1621%</td>\n",
       "      <td>0.1628%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>T</th>\n",
       "      <td>6.4196%</td>\n",
       "      <td>6.4196%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TGT</th>\n",
       "      <td>4.0904%</td>\n",
       "      <td>4.0904%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TMO</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0002%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TXT</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0001%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>VZ</th>\n",
       "      <td>8.3447%</td>\n",
       "      <td>8.3446%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>ZION</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0001%</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          ECOS      SCS\n",
       "APA    0.0000%  0.0000%\n",
       "BA     0.0000%  0.0001%\n",
       "BAX    5.2634%  5.2632%\n",
       "BMY    4.3887%  4.3886%\n",
       "CMCSA  2.1705%  2.1705%\n",
       "CNP    6.9872%  6.9870%\n",
       "CPB    3.2390%  3.2391%\n",
       "DE     0.0789%  0.0791%\n",
       "HPQ    0.0000%  0.0002%\n",
       "JCI    2.8376%  2.8375%\n",
       "JPM    6.9842%  6.9839%\n",
       "LUV    2.8523%  2.8522%\n",
       "MMC   12.5805% 12.5803%\n",
       "MO     7.2314%  7.2313%\n",
       "MSFT   0.0000%  0.0003%\n",
       "NI    11.4509% 11.4508%\n",
       "PCAR   0.0000%  0.0001%\n",
       "PSA   14.9186% 14.9183%\n",
       "SEE    0.1621%  0.1628%\n",
       "T      6.4196%  6.4196%\n",
       "TGT    4.0904%  4.0904%\n",
       "TMO    0.0000%  0.0002%\n",
       "TXT    0.0000%  0.0001%\n",
       "VZ     8.3447%  8.3446%\n",
       "ZION   0.0000%  0.0001%"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#########################################\n",
    "# Minimizing Portfolio Standard Deviation\n",
    "#########################################\n",
    "\n",
    "from scipy.linalg import sqrtm\n",
    "\n",
    "# Defining initial inputs\n",
    "mu = Y.mean().to_numpy().reshape(1,-1)\n",
    "sigma = Y.cov().to_numpy()\n",
    "G = sqrtm(sigma)\n",
    "\n",
    "# Defining initial variables\n",
    "x = cp.Variable((mu.shape[1], 1))\n",
    "g = cp.Variable(nonneg=True)\n",
    "\n",
    "# Budget and weights constraints\n",
    "constraints = [cp.sum(x) == 1,\n",
    "               x >= 0]\n",
    "\n",
    "# Defining risk objective\n",
    "risk = g\n",
    "constraints += [cp.SOC(g, G @ x)] # SOC constraint\n",
    "constraints += [risk <= sigma_hat] # variance constraint\n",
    "objective = cp.Minimize(risk)\n",
    "\n",
    "weights = pd.DataFrame([])\n",
    "# Solving the problem with several solvers\n",
    "prob = cp.Problem(objective, constraints)\n",
    "solvers = ['ECOS', 'SCS']\n",
    "for i in solvers:\n",
    "    prob.solve(solver=i)\n",
    "    # Showing Optimal Weights\n",
    "    weights_1 = pd.DataFrame(x.value, index=assets, columns=[i])\n",
    "    weights = pd.concat([weights, weights_1], axis=1)\n",
    "\n",
    "display(weights)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e4fdaab",
   "metadata": {},
   "source": [
    "As we can see the use of CVXPY's __SOC constraint__ in portfolio optimization solves the error that we see when we use __quad_form__."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "f7ba5cc1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ECOS</th>\n",
       "      <th>SCS</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Return</th>\n",
       "      <td>12.8508%</td>\n",
       "      <td>12.8509%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Std. Dev.</th>\n",
       "      <td>10.3737%</td>\n",
       "      <td>10.3737%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Variance</th>\n",
       "      <td>1.0761%</td>\n",
       "      <td>1.0761%</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              ECOS      SCS\n",
       "Return    12.8508% 12.8509%\n",
       "Std. Dev. 10.3737% 10.3737%\n",
       "Variance   1.0761%  1.0761%"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Calculating Annualized Portfolio Stats\n",
    "var = weights * (Y.cov() @ weights) * 252\n",
    "var = var.sum().to_frame().T\n",
    "std = np.sqrt(var)\n",
    "ret = Y.mean().to_frame().T @ weights * 252\n",
    "\n",
    "stats = pd.concat([ret, std, var], axis=0)\n",
    "stats.index = ['Return', 'Std. Dev.', 'Variance']\n",
    "\n",
    "display(stats)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2b1a7724",
   "metadata": {},
   "source": [
    "### 2.2 Return Maximization with Standard Deviation Constraint\n",
    "\n",
    "The maximization of portfolio return using SOC constraints can be posed as:\n",
    "\n",
    "$$\n",
    "\\begin{equation}\n",
    "\\begin{aligned}\n",
    "& \\underset{x}{\\text{max}} & & \\mu x^{\\tau} \\\\\n",
    "& \\text{s.t.} & & g \\leq \\bar{\\sigma} \\\\\n",
    "& & & \\left\\|\\Sigma^{1/2} x\\right\\| \\leq g \\\\\n",
    "& & & \\sum_{i=1}^{N} x_i = 1 \\\\\n",
    "& & &  x_i \\geq 0 \\; ; \\; \\forall \\; i =1, \\ldots, N \\\\\n",
    "\\end{aligned}\n",
    "\\end{equation}\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "6e1578ed",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ECOS</th>\n",
       "      <th>SCS</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>APA</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0003%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>BA</th>\n",
       "      <td>9.5885%</td>\n",
       "      <td>9.5835%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>BAX</th>\n",
       "      <td>12.6190%</td>\n",
       "      <td>12.6236%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>BMY</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>-0.0011%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CMCSA</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>-0.0010%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CNP</th>\n",
       "      <td>3.7154%</td>\n",
       "      <td>3.7281%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>CPB</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>-0.0014%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>DE</th>\n",
       "      <td>6.2555%</td>\n",
       "      <td>6.2519%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>HPQ</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0006%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>JCI</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>-0.0006%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>JPM</th>\n",
       "      <td>6.5725%</td>\n",
       "      <td>6.5909%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>LUV</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>-0.0008%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MMC</th>\n",
       "      <td>18.7512%</td>\n",
       "      <td>18.7542%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MO</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>-0.0017%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>MSFT</th>\n",
       "      <td>35.7087%</td>\n",
       "      <td>35.6702%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>NI</th>\n",
       "      <td>0.0135%</td>\n",
       "      <td>0.0331%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>PCAR</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>-0.0001%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>PSA</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>-0.0018%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>SEE</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>-0.0007%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>T</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>-0.0015%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TGT</th>\n",
       "      <td>6.7755%</td>\n",
       "      <td>6.7784%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TMO</th>\n",
       "      <td>0.0001%</td>\n",
       "      <td>0.0001%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>TXT</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0001%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>VZ</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>-0.0013%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>ZION</th>\n",
       "      <td>0.0000%</td>\n",
       "      <td>0.0009%</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "          ECOS      SCS\n",
       "APA    0.0000%  0.0003%\n",
       "BA     9.5885%  9.5835%\n",
       "BAX   12.6190% 12.6236%\n",
       "BMY    0.0000% -0.0011%\n",
       "CMCSA  0.0000% -0.0010%\n",
       "CNP    3.7154%  3.7281%\n",
       "CPB    0.0000% -0.0014%\n",
       "DE     6.2555%  6.2519%\n",
       "HPQ    0.0000%  0.0006%\n",
       "JCI    0.0000% -0.0006%\n",
       "JPM    6.5725%  6.5909%\n",
       "LUV    0.0000% -0.0008%\n",
       "MMC   18.7512% 18.7542%\n",
       "MO     0.0000% -0.0017%\n",
       "MSFT  35.7087% 35.6702%\n",
       "NI     0.0135%  0.0331%\n",
       "PCAR   0.0000% -0.0001%\n",
       "PSA    0.0000% -0.0018%\n",
       "SEE    0.0000% -0.0007%\n",
       "T      0.0000% -0.0015%\n",
       "TGT    6.7755%  6.7784%\n",
       "TMO    0.0001%  0.0001%\n",
       "TXT    0.0000%  0.0001%\n",
       "VZ     0.0000% -0.0013%\n",
       "ZION   0.0000%  0.0009%"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#########################################\n",
    "# Maximizing Portfolio Return with\n",
    "# Standard Deviation Constraint\n",
    "#########################################\n",
    "\n",
    "from scipy.linalg import sqrtm\n",
    "\n",
    "# Defining initial inputs\n",
    "mu = Y.mean().to_numpy().reshape(1,-1)\n",
    "sigma = Y.cov().to_numpy()\n",
    "G = sqrtm(sigma)\n",
    "\n",
    "# Defining initial variables\n",
    "x = cp.Variable((mu.shape[1], 1))\n",
    "g = cp.Variable(nonneg=True)\n",
    "sigma_hat = 15 / (252**0.5 * 100)\n",
    "ret = mu @ x\n",
    "\n",
    "# Budget and weights constraints\n",
    "constraints = [cp.sum(x) == 1,\n",
    "               x <= 1,\n",
    "               x >= 0]\n",
    "\n",
    "\n",
    "# Defining risk constraint and objective\n",
    "risk = g\n",
    "constraints += [cp.SOC(g, G @ x)] # SOC constraint\n",
    "constraints += [risk <= sigma_hat] # standard deviation constraint\n",
    "objective = cp.Maximize(ret)\n",
    "\n",
    "weights = pd.DataFrame([])\n",
    "# Solving the problem with several solvers\n",
    "prob = cp.Problem(objective, constraints)\n",
    "solvers = ['ECOS', 'SCS']\n",
    "for i in solvers:\n",
    "    prob.solve(solver=i)\n",
    "    # Showing Optimal Weights\n",
    "    weights_1 = pd.DataFrame(x.value, index=assets, columns=[i])\n",
    "    weights = pd.concat([weights, weights_1], axis=1)\n",
    "\n",
    "display(weights)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "30e42609",
   "metadata": {},
   "source": [
    "CVXPY's __SOC constraint__ also solves the error that we see when we use __quad_form__ in constraints."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "7dc3764c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>ECOS</th>\n",
       "      <th>SCS</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Return</th>\n",
       "      <td>26.0352%</td>\n",
       "      <td>26.0316%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Std. Dev.</th>\n",
       "      <td>15.0000%</td>\n",
       "      <td>14.9958%</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Variance</th>\n",
       "      <td>2.2500%</td>\n",
       "      <td>2.2487%</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "              ECOS      SCS\n",
       "Return    26.0352% 26.0316%\n",
       "Std. Dev. 15.0000% 14.9958%\n",
       "Variance   2.2500%  2.2487%"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Calculating Annualized Portfolio Stats\n",
    "var = weights * (Y.cov() @ weights) * 252\n",
    "var = var.sum().to_frame().T\n",
    "std = np.sqrt(var)\n",
    "ret = Y.mean().to_frame().T @ weights * 252\n",
    "\n",
    "stats = pd.concat([ret, std, var], axis=0)\n",
    "stats.index = ['Return', 'Std. Dev.', 'Variance']\n",
    "\n",
    "display(stats)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "80e0bd8f",
   "metadata": {},
   "source": [
    "For more portfolio optimization models and applications, you can see the CVXPY based library __[Riskfolio-Lib](https://github.com/dcajasn/Riskfolio-Lib)__."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
